package com.example.demo.controller;

import com.example.demo.common.Func;
import com.example.demo.common.Result;
import com.example.demo.exception.BusinessException;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import com.github.xiaoymin.knife4j.annotations.ApiSupport;
import com.jcraft.jsch.*;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;

@RestController
@RequestMapping("/api/shell")
@Api(tags = "19、远程Shell管理")
@ApiSupport(author = "罗海林", order = 19)
@Validated
public class ShellController {

    private static final String hostName = "120.24.167.199";
    private static final String userName = "dahai";
    private static final String password = "66dOYvnMaLyNMnz2";
    private static final int port = 22;

    @PostMapping("/viewFile")
    @ApiOperation(value = "查看服务器文件", response = Result.class)
    @ApiOperationSupport(author = "罗海林", order = 1)
    public Result viewFile() {
        Session session = null;
        ChannelSftp sftpChannel = null;
        StringBuilder content = new StringBuilder();
        BufferedReader bufferedReader = null;
        InputStream inputStream = null;
        try {
            JSch jsch = new JSch();
            // 建立会话
            session = jsch.getSession(userName, hostName, port);
            // 设置登录密码
            session.setPassword(password);
            // 不做主机密钥检查（生产环境中请谨慎处理）
            session.setConfig("StrictHostKeyChecking", "no");
            // 建立连接
            session.connect();

            // 打开sftp通道类型
            sftpChannel = (ChannelSftp) session.openChannel("sftp");
            // 建立通道连接
            sftpChannel.connect();
            // 远程主机文件的详细路径
            inputStream = sftpChannel.get("/opt/autoCheck.sh");

            String line;
            bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
            while ((line = bufferedReader.readLine()) != null) {
                Func.print(line);
                content.append(line).append("\\n");
            }
        }
        catch (Exception ex) {
            throw new BusinessException(ex.toString());
        }
        finally {
            try {
                if (bufferedReader != null) {
                    bufferedReader.close();
                }
            } catch (Exception ignored) { }

            try {
                if (inputStream != null) {
                    inputStream.close();
                }
            } catch (Exception ignored) { }

            if (sftpChannel != null && sftpChannel.isConnected()) {
                sftpChannel.disconnect();
            }
            if (session != null && session.isConnected()) {
                session.disconnect();
            }
        }

        Result res = new Result().ok();
        res.put("content", content.toString());
        return res;
    }

    @PostMapping("/executeCommand")
    @ApiOperation(value = "执行服务器命令", response = Result.class)
    @ApiOperationSupport(author = "罗海林", order = 2)
    public Result executeCommand() {
        Session session = null;
        Channel channel = null;
        InputStream inputStream = null;
        try {
            JSch jsch = new JSch();
            // 建立会话
            session = jsch.getSession(userName, hostName, port);
            // 设置登录密码
            session.setPassword(password);
            // 不做主机密钥检查（生产环境中请谨慎处理）
            session.setConfig("StrictHostKeyChecking", "no");
            // 建立连接
            session.connect();

            // 将要执行的命令
            String command = "ls /opt";
            // 打开exec类型的通道；该通道用来实现执行远程主机的命令
            channel = session.openChannel("exec");
            // 设置执行的命令
            ((ChannelExec) channel).setCommand(command);
            channel.setInputStream(null);
            // 当发送错误是，将错误输出到控制台
            ((ChannelExec) channel).setErrStream(System.err);

            // 建立连接后获取执行命令的输出结果信息
            inputStream = channel.getInputStream();
            channel.connect();
            byte[] tmp = new byte[1024];
            while (true) {
                while (inputStream.available() > 0) {
                    int i = inputStream.read(tmp, 0, 1024);
                    if (i < 0) {
                        break;
                    }
                    Func.print(new String(tmp, 0, i));
                }

                if (channel.isClosed()) {
                    if (inputStream.available() > 0) {
                        continue;
                    }
                    break;
                }
            }
        }
        catch (Exception ex) {
            throw new BusinessException(ex.toString());
        }
        finally {
            try {
                if (inputStream != null) {
                    inputStream.close();
                }
            } catch (Exception ignored) { }

            if (channel != null && channel.isConnected()) {
                channel.disconnect();
            }
            if (session != null && session.isConnected()) {
                session.disconnect();
            }
        }

        Result res = new Result().ok();
        return res;
    }

    @PostMapping("/getShellCode")
    @ApiOperation(value = "获取Shell命令符", response = Result.class)
    @ApiOperationSupport(author = "罗海林", order = 3)
    public Result getShellCode() {
        Session session = null;
        Channel channel = null;
        try {
            JSch jsch = new JSch();
            // 建立会话
            session = jsch.getSession(userName, hostName, port);
            // 设置登录密码
            session.setPassword(password);
            // 不做主机密钥检查（生产环境中请谨慎处理）
            session.setConfig("StrictHostKeyChecking", "no");
            // 建立连接
            session.connect();

            // 打开shell类型的通道
            channel = session.openChannel("shell");
            // 输入的指令由终端用户输入
            channel.setInputStream(System.in);
            // 控制台输出
            channel.setOutputStream(System.out);
            // 建立连接
            channel.connect(3 * 1000);
        }
        catch (Exception ex) {
            throw new BusinessException(ex.toString());
        }
        finally {
            /*if (channel != null && channel.isConnected()) {
                channel.disconnect();
            }
            if (session != null && session.isConnected()) {
                session.disconnect();
            }*/
        }

        Result res = new Result().ok();
        return res;
    }

}
